import { useStore as useAnalysisStore } from "@/store/analysis";
import { computed, ref } from "vue";
import _ from "lodash";
import { Midi } from "@tonejs/midi";
import { getMultiple } from "@/common/utils/museXmlDeal";
export default () => {
  const stateOri = {
    scale: "",
    tempo: 0,
    lyrics: [] as any[],
    beat: "" as any,
  }
  const state = ref(_.cloneDeep(stateOri));
  const tempDataOri = {
    midCount: 0, //mid循环计数
    firstChordIdx: 0, //第一个和弦
    xmlCount: 0, //xml循环计数
    lyricsIdx: -1,
    duration: 0,
    tiedStarts: {}, //连音起始标记
    chordIdx: -1,
  }
  const tempData = ref(_.cloneDeep(tempDataOri));
  const result = computed(() => {
    return {
      temp: ((60 / state.value.tempo) * 1000000).toFixed(0),
      beat: state.value.beat,
      scale: state.value.scale,
      lyrics: state.value.lyrics,
    }
  })
  const analysisStore = useAnalysisStore();
  const initState = () => {
    state.value = _.cloneDeep(stateOri);
  }
  const initTempData = () => {
    tempData.value = _.cloneDeep(tempDataOri);
  }
  const isWord = (note: any) => {
    return note.word;
  }
  const isChord = (note: any) => {
    return note.choose && note.beat;
  }
  const dealFile = async (midFile) => {
    initState();
    initTempData();
    const midRes = await Midi.fromUrl(midFile);
    const midNotes = midRes?.tracks?.[0]?.notes || [];
    state.value.beat = midRes?.header?.ppq;
    let tempo = Number(midRes?.header?.tempos?.[0]?.bpm?.toFixed(0) || "");
    state.value.tempo = tempo;
    // 组装xml数组
    let xmlList: any[] = [];
    analysisStore.xmlData.measures.forEach((measuresItem, measuresIdx) => {
      const multiple = getMultiple(measuresItem);
      measuresItem.forEach((noteItem, noteIdx) => {
        noteItem.multiple = multiple;
        xmlList.push(noteItem);
      })
    })
    tempData.value.firstChordIdx = xmlList.findIndex(x => isChord(x));
    // 连音起始位置记录
    let tiedStopTemp:number[] = [];
    // 处理mid文件数据
    xmlList.forEach((noteItem, noteIdx) => {
      if (!noteItem.isRest && !noteItem.isGrace) {
        if (noteItem.isTiedStart) {
          tiedStopTemp.push(tempData.value.midCount);
        }
        if (noteItem.isTiedStop) {
          // 取出记录第一项,先进先出
          const idx = tiedStopTemp.shift() || tempData.value.midCount - 1;
          noteItem.midi = midNotes[idx].midi;
          noteItem.velocity = String(midNotes[idx].velocity * 127);
        } else {
          noteItem.midi = midNotes[tempData.value.midCount]?.midi;
          noteItem.velocity = String(midNotes[tempData.value.midCount]?.velocity * 127);
          tempData.value.midCount++;
        }
      }
    })
    xmlList.forEach((noteItem, noteIdx) => {
      if (noteItem.isGrace) {
        return;
      }

      // 如果是连音结束直接取出
      let tiedStart: any = null;
      if (noteItem.isTiedStop) {
        tiedStart = _.cloneDeep(tempData.value.tiedStarts[noteItem.midi]);
      }
      if (isChord(noteItem)) {
        tempData.value.duration = 0;
      }
      // 在第一个和弦之前的文字,仅放入文字
      if (noteIdx < tempData.value.firstChordIdx) {
        if (isWord(noteItem)) {
          state.value.lyrics.push({
            word: noteItem.word,
            breakLine: noteItem.breakLine || 0,
            repeatWord: noteItem.repeatWord || 0,
          })
          tempData.value.lyricsIdx++;
        }
      } else {
        if (isWord(noteItem) || isChord(noteItem)) {
          let obj: any = {
            word: noteItem.word || "",
            melody: [],
            breakLine: noteItem.breakLine || 0,
            repeatWord: noteItem.repeatWord || 0,
          }
          noteItem.beat && (obj.beat = noteItem.beat);
          noteItem.chooseOri && (obj.chooseOri = noteItem.chooseOri);
          noteItem.chooseScore && (obj.chooseScore = noteItem.chooseScore);
          noteItem.choose && (obj.choose = noteItem.choose);
          state.value.lyrics.push(obj);
          if (isChord(noteItem)) {
            tempData.value.chordIdx = state.value.lyrics.length - 1;
          }
          tempData.value.lyricsIdx++;
        }
        if (!noteItem.isRest) {
          // 多音时，回退duration保持所有音符起始duration一致
          if (noteItem.isChord) {
            tempData.value.duration = noteIdx === tempData.value.firstChordIdx ? 0 : tempData.value.duration - noteItem.duration * noteItem.multiple;
          }
          let melody_d: any = {
            Note: noteItem.midi,
            Velocity: noteItem.velocity,
            duration: tempData.value.duration,
          }

          // 当是连音结束的音符时
          if (noteItem.isTiedStop) {
            // 如果不是同时是连音开始的音符,释放音符按下记录
            if (!noteItem.isTiedStart) {
              delete tempData.value.tiedStarts[noteItem.midi];
            }
            // 当标记和弦时,不延长时间,视为休止符
            if (isWord(noteItem) || isChord(noteItem)) {
              melody_d.Note = "0";
              melody_d.Velocity = xmlList?.[noteIdx - 1]?.velocity || "0";
            } else {
              //否则,延长连音起始note的duration  且不进行push操作
              let idx = 0;
              let idy = 0;
              if (tiedStart && tiedStart.idx >= 0 && tiedStart.idy >= 0) {
                idx = tiedStart.idx;
                idy = tiedStart.idy;
              } else {
                // 当前melody为空时回退上一melody
                idx = state.value.lyrics[state.value.lyrics.length - 1].melody.length > 0 ? state.value.lyrics.length - 1 : state.value.lyrics.length - 2;
                idy = state.value.lyrics[idx].melody.length - 2;
              }
              // 延音不能超过和弦的拍数
              const _beat = Number(state.value.lyrics?.[tempData.value.chordIdx]?.beat);
              let _duration = state.value.lyrics[idx].melody[idy + 1].duration + noteItem.duration * noteItem.multiple;
              state.value.lyrics[idx].melody[idy + 1].duration = (_beat && _duration > _beat) ? _beat : _duration;
              melody_d.Note = null;
            }
          }
          tempData.value.duration = tempData.value.duration + noteItem.duration * noteItem.multiple;
          // 推入
          if (melody_d.Note !== null) {
            state.value.lyrics[tempData.value.lyricsIdx].melody.push({
              Note: melody_d.Note,
              Velocity: melody_d.Velocity,
              duration: melody_d.duration,
            })
            state.value.lyrics[tempData.value.lyricsIdx].melody.push({
              Note: melody_d.Note,
              Velocity: "0",
              duration: tempData.value.duration,
            })
          }
        } else {
          if (isChord(noteItem)) {
            // 休止符处理
            state.value.lyrics[tempData.value.lyricsIdx].melody.push({
              Note: "0",
              Velocity: xmlList?.[noteIdx - 1]?.velocity || "0",
              duration: tempData.value.duration,
            })
            tempData.value.duration = tempData.value.duration + noteItem.duration * noteItem.multiple;
            state.value.lyrics[tempData.value.lyricsIdx].melody.push({
              Note: "0",
              Velocity: "0",
              duration: tempData.value.duration,
            })
          } else {
            // 无和弦休止符特殊处理
            tempData.value.duration = tempData.value.duration + noteItem.duration * noteItem.multiple;
            let idx = tempData.value.lyricsIdx;
            // 当前melody为空时回退上一melody
            state.value.lyrics[idx].melody.length > 0 || (idx = idx - 1);
            state.value.lyrics[idx].melody[state.value.lyrics[idx].melody.length - 1].duration = tempData.value.duration;
          }
        }
      }
      // 如果是连音开始标记存入
      if (noteIdx >= tempData.value.firstChordIdx && noteItem.isTiedStart) {
        // 不是连音结束时，才更新记录； 但如果是和弦位或歌词位，是连音结束时也更新记录
        if (!noteItem.isTiedStop || (isWord(noteItem) || isChord(noteItem))) {
          const idx = tempData.value.lyricsIdx;
          const idy = state.value.lyrics[idx].melody.length - 2;
          tempData.value.tiedStarts[noteItem.midi] = { idx, idy };
        }
      }
    })
    analysisStore.setResult({
      temp: result.value.temp,
      beat: result.value.beat,
      lyrics: result.value.lyrics,
    })
    return true;
  }
  return {
    dealFile,
    state,
    result,
  }
}